package jumpingnotes.service.remoting;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import jumpingnotes.model.ActivityType;
import jumpingnotes.model.ErrorType;
import jumpingnotes.model.ResourceTypes;
import jumpingnotes.model.Result;
import jumpingnotes.model.entity.*;
import jumpingnotes.util.ImageHelper;
import jumpingnotes.storage.StorageService;

public class BookServiceImpl extends GenericService implements BookService{

	private static String [] BookAttribute = {"name","sub_title","abstract","author","author_intro",
		"publish_press","publish_year","chapter_count","word_count","complete_status","website","url"};
	
	private static String [] ChapterAttribute = {"number","name","abstract","uuid"};
	
	private ImageHelper imageHelper;
	private StorageService storageService;
	
	public void setImageHelper(ImageHelper imageHelper) {
		this.imageHelper = imageHelper;
	}
	
	public void setStorageService(StorageService storageService) {
		this.storageService = storageService;
	}	
	
	private void bookVersionDetailCreate(String memberID, String bookID, String property, String value, int weight)
	{
		BookVersion bookVersion = new BookVersion();
		bookVersion.setCreateTime(new Date());
		bookVersion.setUpdateTime(new Date());
		bookVersion.setProperty(property);
		bookVersion.setValue(value);
		bookVersion.setWeight(weight);
		bookVersion.setBook(accessService.findBookById(Integer.parseInt(bookID)));
		bookVersion.setMemberId(Integer.parseInt(memberID));
		accessService.saveBookVersion(bookVersion);
	}
	
	private void chapterVersionDetailCreate(String memberID, String chapterID, String property, String value, int weight)
	{
		ChapterVersion chapterVersion = new ChapterVersion();
		chapterVersion.setCreateTime(new Date());
		chapterVersion.setUpdateTime(new Date());
		chapterVersion.setProperty(property);
		chapterVersion.setValue(value);
		chapterVersion.setWeight(weight);
		chapterVersion.setChapter(accessService.findChapterById(Integer.parseInt(chapterID)));
		chapterVersion.setMemberId(Integer.parseInt(memberID));
		accessService.saveChapterVersion(chapterVersion);
	}
	
	private String bookInfoVersionCompute(Set<BookVersion> s, String property)
	{		
		String finalValue = null;
		Integer maxWeight = Integer.MIN_VALUE;
		
		if(s != null && s.size() > 0)
		{
			for(BookVersion bookVersion : s)
			{
				if(bookVersion.getProperty().equals(property) && 
						bookVersion.getWeight() > maxWeight)
				{
					maxWeight = bookVersion.getWeight();
					finalValue = bookVersion.getValue();
				}
			}
			return finalValue;
		}
		return null;
	}
	
	private String chapterInfoVersionCompute(Set<ChapterVersion> s, String property)
	{
		String finalValue = null;
		Integer maxWeight = Integer.MIN_VALUE;
		
		if(s != null && s.size() > 0)
		{
			for(ChapterVersion chapterVersion : s)
			{
				if(chapterVersion.getProperty().equals(property) 
						&& chapterVersion.getWeight() > maxWeight)
				{
					maxWeight = chapterVersion.getWeight();
					finalValue = chapterVersion.getValue();
				}
			}
			return finalValue;
		}
		return null;
	}
	
	public Result bookCreate(String bookName, String author, String memberID)
	{
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);
		Book book = new Book();
		book.setCreateTime(new Date());
		book.setUpdateTime(new Date());
		book.setName(bookName);
		book.setAuthor(author);
		book.setMemberId(Integer.parseInt(memberID));
		accessService.saveBook(book);
		
		ActivityTemplateParam[] activityParams = new ActivityTemplateParam[2];
		activityParams[0] = new ActivityTemplateParam();
		activityParams[0].setName("member");
		activityParams[0].setValue(member.getMemberId() + "&" + member.getNickName());
		activityParams[1] = new ActivityTemplateParam();
		activityParams[1].setName("book");
		activityParams[1].setValue(book.getBookId() + "&" + book.getName());
		ActivityMediaItem[] mediaItems = new ActivityMediaItem[1];
		mediaItems[0] = new ActivityMediaItem();
		mediaItems[0].setMimeType(String.valueOf(ResourceTypes.TYPE_IMAGE));
		mediaItems[0].setUrl(book.getImage());		
		memberActivityCreate(memberID, ActivityType.MEMBER_INFO_UPDATE, activityParams, mediaItems, null, "1");		
		
		return new Result(book.getBookId());
	}
	
	public Result bookInfoVersionCreate(String bookID, String name,
			String subTitle, String abstract_, String author,
			String authorIntro, String publishPress, String publishYear,
			String chapterCount, String wordCount, String completeStatus,
			String website, String url, String memberID)
	{
		//getBook
		Book book = accessService.findBookById(Integer.parseInt(bookID));
		if(book == null)
			return new Result(ErrorType.BOOK_NOT_EXIST);
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);
		int weight = 1; // should be computed
		// prepare parameter
		List<String> parameterList = new ArrayList<String>();
		parameterList.add(name);
		parameterList.add(subTitle);
		parameterList.add(abstract_);
		parameterList.add(author);
		parameterList.add(authorIntro);
		parameterList.add(publishPress);
		parameterList.add(publishYear);
		parameterList.add(chapterCount);
		parameterList.add(wordCount);
		parameterList.add(completeStatus);
		parameterList.add(website);
		parameterList.add(url);
		
		// create book Version
		for(int i=0;i<BookAttribute.length;i++)
		{
			bookVersionDetailCreate(memberID,bookID,BookAttribute[i],parameterList.get(i),weight);
		}
		
		// update book information
		Set<BookVersion> s = book.getBookVersions();
		book.setUpdateTime(new Date());
		book.setName(bookInfoVersionCompute(s,BookAttribute[0]));
		book.setSubTitle(bookInfoVersionCompute(s,BookAttribute[1]));
		book.setAbstract_(bookInfoVersionCompute(s,BookAttribute[2]));
		book.setAuthor(bookInfoVersionCompute(s,BookAttribute[3]));
		book.setAuthorIntro(bookInfoVersionCompute(s,BookAttribute[4]));
		book.setPublishPress(bookInfoVersionCompute(s,BookAttribute[5]));
		book.setPublishYear(bookInfoVersionCompute(s,BookAttribute[6]));
		book.setChapterCount(Integer.parseInt(bookInfoVersionCompute(s,BookAttribute[7])));
		book.setWordCount(Integer.parseInt(bookInfoVersionCompute(s,BookAttribute[8])));
		book.setCompleteStatus(Integer.parseInt(bookInfoVersionCompute(s,BookAttribute[9])));
		book.setWebsite(bookInfoVersionCompute(s,BookAttribute[10]));
		book.setUrl(bookInfoVersionCompute(s,BookAttribute[11]));
		accessService.updateBook(book);
		return new Result();
	}
	
	public Result bookCoverVersionUpload(String bookID, String memberID, String image)
	{
		Book book = accessService.findBookById(Integer.parseInt(bookID));
		if(book == null)
			return new Result(ErrorType.BOOK_NOT_EXIST);
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);
		int weight = 1;// should be computed
		bookVersionDetailCreate(memberID,bookID,"image",image,weight);
		String finalImage = bookInfoVersionCompute(book.getBookVersions(),"image");
		// update image
		book.setImage(finalImage);
		accessService.updateBook(book);
		return new Result();
	}
	
	public Result chapterCreate(String bookID, String memberID, String name, int number, String abstract_, String uuid)
	{
		Book book = accessService.findBookById(Integer.parseInt(bookID));
		if(book == null)
			return new Result(ErrorType.BOOK_NOT_EXIST);
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);
		Chapter chapter = new Chapter();
		chapter.setBook(book);
		chapter.setMemberId(Integer.parseInt(memberID));
		chapter.setName(name);
		chapter.setNumber(number);
		chapter.setAbstract_(abstract_);
		chapter.setUuid(uuid);
		chapter.setCreateTime(new Date());
		chapter.setUpdateTime(new Date());
		accessService.saveChapter(chapter);
		
		ActivityTemplateParam[] activityParams = new ActivityTemplateParam[3];
		activityParams[0] = new ActivityTemplateParam();
		activityParams[0].setName("member");
		activityParams[0].setValue(member.getMemberId() + "&" + member.getNickName());
		activityParams[1] = new ActivityTemplateParam();
		activityParams[1].setName("book");
		activityParams[1].setValue(book.getBookId() + "&" + book.getName());
		activityParams[2] = new ActivityTemplateParam();
		activityParams[2].setName("chapter");
		activityParams[2].setValue(chapter.getChapterId() + "&" + chapter.getName());
		ActivityMediaItem[] mediaItems = new ActivityMediaItem[1];
		mediaItems[0] = new ActivityMediaItem();
		mediaItems[0].setMimeType(String.valueOf(ResourceTypes.TYPE_IMAGE));
		mediaItems[0].setUrl(book.getImage());		
		memberActivityCreate(memberID, ActivityType.BOOK_CHAPTER_UPLOAD, activityParams, mediaItems, null, "1");				
		
		return new Result(chapter.getChapterId());
	}
	
	public Result chapterVersionCreate(String chapterID, String memberID,String number, String name,String abstract_, String uuid)
	{
		// check
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);
		Chapter chapter = accessService.findChapterById(Integer.parseInt(chapterID));
		if(chapter == null)
			return new Result(ErrorType.BOOK_CHAPTER_NOT_EXIST);
		// create book Version
		int weight = 1;
		chapterVersionDetailCreate(memberID,chapterID,ChapterAttribute[0],number,weight);
		chapterVersionDetailCreate(memberID,chapterID,ChapterAttribute[1],name,weight);
		chapterVersionDetailCreate(memberID,chapterID,ChapterAttribute[2],abstract_,weight);
		chapterVersionDetailCreate(memberID,chapterID,ChapterAttribute[3],uuid,weight);
		
		// update chapter information 
		Set<ChapterVersion> s = chapter.getChapterVersions();
		chapter.setUpdateTime(new Date());
		chapter.setNumber(Integer.parseInt(chapterInfoVersionCompute(s,ChapterAttribute[0])));
		chapter.setName(chapterInfoVersionCompute(s,ChapterAttribute[1]));
		chapter.setAbstract_(chapterInfoVersionCompute(s,ChapterAttribute[2]));
		chapter.setUuid(chapterInfoVersionCompute(s,ChapterAttribute[3]));
		accessService.updateChapter(chapter);
		return new Result();
	}
	
	public Result bookFavoriteCreate(String bookID, String memberID)
	{
		//check
		Book book = accessService.findBookById(Integer.parseInt(bookID));
		if(book == null)
			return new Result(ErrorType.BOOK_NOT_EXIST);
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);
		//do check
		BookFavorite bookFavorite = new BookFavorite();
		// TODO memberId of BookFavorite has been changed to int
		// bookFavorite.setMemberId(memberID);
		List<BookFavorite> list = accessService.findAllBookFavorite(bookFavorite);
		if(list != null && list.size()>0)
		{
			for(BookFavorite favorite:list)
				if(favorite.getBook().getBookId().equals(book.getBookId()))
					return new Result(ErrorType.BOOK_FAVORITE_EXIST);
		}

		bookFavorite.setBook(book);
		bookFavorite.setCreateTime(new Date());
		bookFavorite.setMember(member);
		accessService.saveBookFavorite(bookFavorite);
		
		ActivityTemplateParam[] activityParams = new ActivityTemplateParam[2];
		activityParams[0] = new ActivityTemplateParam();
		activityParams[0].setName("member");
		activityParams[0].setValue(member.getMemberId() + "&" + member.getNickName());
		activityParams[1] = new ActivityTemplateParam();
		activityParams[1].setName("book");
		activityParams[1].setValue(book.getBookId() + "&" + book.getName());
		ActivityMediaItem[] mediaItems = new ActivityMediaItem[1];
		mediaItems[0] = new ActivityMediaItem();
		mediaItems[0].setMimeType(String.valueOf(ResourceTypes.TYPE_IMAGE));
		mediaItems[0].setUrl(book.getImage());		
		memberActivityCreate(memberID, ActivityType.BOOK_FAVORITE_CREATE, activityParams, mediaItems, null, "1");				
			
		return new Result(bookFavorite.getBookFavoriteId());
	}
	
	public Result bookFavoriteDelete(String bookID, String memberID)
	{
		//check
		Book book = accessService.findBookById(Integer.parseInt(bookID));
		if(book == null)
			return new Result(ErrorType.BOOK_NOT_EXIST);
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);
		
		// TODO memberId of BookFavorite has been changed to int
		BookFavorite bookFavorite = new BookFavorite();
		// bookFavorite.setMemberId(Integer.parseInt(memberID));
		List<BookFavorite> list = accessService.findAllBookFavorite(bookFavorite);	
		if(list != null && list.size()>0)
		{
			for(BookFavorite favorite:list)
				if(favorite.getBook().getBookId().equals(book.getBookId()))
				{
					accessService.deleteBookFavorite(favorite);
				}
		}
		
		return new Result();
	}
	
	public Result bookCommentCreate(String bookID, String memberID, String comment)
	{
		//check
		Book book = accessService.findBookById(Integer.parseInt(bookID));
		if(book == null)
			return new Result(ErrorType.BOOK_NOT_EXIST);
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);
		
		BookComment bookComment = new BookComment();
		bookComment.setCreateTime(new Date());
		bookComment.setBody(comment);
		bookComment.setBook(book);
		bookComment.setMember(member);
		accessService.saveBookComment(bookComment);
		
		ActivityTemplateParam[] activityParams = new ActivityTemplateParam[2];
		activityParams[0] = new ActivityTemplateParam();
		activityParams[0].setName("member");
		activityParams[0].setValue(member.getMemberId() + "&" + member.getNickName());
		activityParams[1] = new ActivityTemplateParam();
		activityParams[1].setName("book");
		activityParams[1].setValue(book.getBookId() + "&" + book.getName());
		ActivityMediaItem[] mediaItems = new ActivityMediaItem[1];
		mediaItems[0] = new ActivityMediaItem();
		mediaItems[0].setMimeType(String.valueOf(ResourceTypes.TYPE_IMAGE));
		mediaItems[0].setUrl(book.getImage());		
		memberActivityCreate(memberID, ActivityType.BOOK_COMMENT, activityParams, mediaItems, null, "1");				
			
		return new Result(bookComment.getBookCommentId());
	}
	
	public Result bookCommentDelete(String bookCommentID, String memberID)
	{
		//check
		BookComment bookComment = accessService.findBookCommentById(Integer.parseInt(bookCommentID));
		if(bookComment == null)
			return new Result(ErrorType.BOOK_COMMENT_NOT_EXIST);
		// check authority
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);
		// check 
		accessService.deleteBookComment(bookComment);
		return new Result();
	}

	@Override
	public Result bookExpectCreate(String bookID, String memberID, String reason) {
		// TODO Auto-generated method stub
		//check
		Book book = accessService.findBookById(Integer.parseInt(bookID));
		if(book == null)
			return new Result(ErrorType.BOOK_NOT_EXIST);
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);

		BookExpect be = new BookExpect();
		be.setBook(book);
		be.setCreateTime(new Date());
		be.setMember(member);
		be.setReason(reason);
		int beId = accessService.saveBookExpect(be);
		
		ActivityTemplateParam[] activityParams = new ActivityTemplateParam[2];
		activityParams[0] = new ActivityTemplateParam();
		activityParams[0].setName("member");
		activityParams[0].setValue(member.getMemberId() + "&" + member.getNickName());
		activityParams[1] = new ActivityTemplateParam();
		activityParams[1].setName("book");
		activityParams[1].setValue(book.getBookId() + "&" + book.getName());
		ActivityMediaItem[] mediaItems = new ActivityMediaItem[1];
		mediaItems[0] = new ActivityMediaItem();
		mediaItems[0].setMimeType(String.valueOf(ResourceTypes.TYPE_IMAGE));
		mediaItems[0].setUrl(book.getImage());		
		memberActivityCreate(memberID, ActivityType.BOOK_EXPECT_CREATE, activityParams, mediaItems, null, "1");				
	
		return new Result(new Integer(beId));
	}

	@Override
	public Result bookRecommendCreate(String bookID, String memberID,
			String target, String reason) {
		// TODO Auto-generated method stub
		//check
		Book book = accessService.findBookById(Integer.parseInt(bookID));
		if(book == null)
			return new Result(ErrorType.BOOK_NOT_EXIST);
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);
		
		BookRecommend br = new BookRecommend();
		br.setBook(book);
		br.setCreateTime(new Date());
		br.setMember(member);
		br.setReason(reason);
		br.setTarget(target);
		int brId = accessService.saveBookRecommend(br);

		ActivityTemplateParam[] activityParams = new ActivityTemplateParam[2];
		activityParams[0] = new ActivityTemplateParam();
		activityParams[0].setName("member");
		activityParams[0].setValue(member.getMemberId() + "&" + member.getNickName());
		activityParams[1] = new ActivityTemplateParam();
		activityParams[1].setName("book");
		activityParams[1].setValue(book.getBookId() + "&" + book.getName());
		ActivityMediaItem[] mediaItems = new ActivityMediaItem[1];
		mediaItems[0] = new ActivityMediaItem();
		mediaItems[0].setMimeType(String.valueOf(ResourceTypes.TYPE_IMAGE));
		mediaItems[0].setUrl(book.getImage());		
		memberActivityCreate(memberID, ActivityType.BOOK_RECOMMEND_CREATE, activityParams, mediaItems, null, "1");				
			
		// If necessary, send emails
		return new Result(new Integer(brId));
	}

	@Override
	public Result errorReportCreate(String memberID, String targetID,
			String subject, String body) {
		// TODO Auto-generated method stub
		Member member = accessService.findMemberById(Integer.parseInt(memberID));
		if(member == null)
			return new Result(ErrorType.USER_NOT_EXIST);

		ErrorReport er = new ErrorReport();
		er.setBody(body);
		//er.setStatus(status);
		er.setSubject(subject);
		er.setMemberId(new Integer(memberID));
		//er.setTargetId(new Integer(targetID));
		er.setCreateTime(new Date());
		int erId = accessService.saveErrorReport(er);

		ActivityTemplateParam[] activityParams = new ActivityTemplateParam[1];
		activityParams[0] = new ActivityTemplateParam();
		activityParams[0].setName("member");
		activityParams[0].setValue(member.getMemberId() + "&" + member.getNickName());
		memberActivityCreate(memberID, ActivityType.ERROR_REPORT_CREATE, activityParams, null, null, "1");				
				
		return new Result(new Integer(erId));
	}

	@Override
	public Result countMemberByFavoriteBook(String bookID) {
		// TODO Auto-generated method stub
		int bookId = Integer.parseInt(bookID);
		Book book = accessService.findBookById(bookId);
		if (book == null)
			return new Result(ErrorType.BOOK_NOT_EXIST);
		return new Result(new Long(queryService.countMemberByFavoriteBook(bookId)));
	}

	@Override
	public Result bookCoverFilter(String uuid, String subtype, String ratio,
			String x, String y, String width, String height) {
		// TODO Auto-generated method stub
		String tmpUuid = uuid;
		// Zoom if required
		String zoomUuid;
		if (ratio != null)
		{
			zoomUuid = UUID.randomUUID().toString();
			try
			{
				imageHelper.zoom(
					storageService.getObjectLocation(ResourceTypes.TYPE_IMAGE, Integer.parseInt(subtype), tmpUuid),
					storageService.getObjectLocation(ResourceTypes.TYPE_IMAGE, Integer.parseInt(subtype), zoomUuid),
					(double)Integer.parseInt(ratio) / 100
					);
				storageService.removeTmpObject(ResourceTypes.TYPE_IMAGE, Integer.parseInt(subtype), tmpUuid);
				tmpUuid = zoomUuid;
			}
			catch (Exception e)
			{
				e.printStackTrace();
				return new Result(ErrorType.SYSTEM_ERROR);
			}
		}

		// Crop if required
		String cropUuid;
		if (x != null)
		{
			cropUuid = UUID.randomUUID().toString();
			try
			{
				imageHelper.crop(
					storageService.getObjectLocation(ResourceTypes.TYPE_IMAGE, Integer.parseInt(subtype), tmpUuid),
					storageService.getObjectLocation(ResourceTypes.TYPE_IMAGE, Integer.parseInt(subtype), cropUuid),
					Integer.parseInt(x),
					Integer.parseInt(y),
					Integer.parseInt(width),
					Integer.parseInt(height)
					);
				storageService.removeTmpObject(ResourceTypes.TYPE_IMAGE, Integer.parseInt(subtype), tmpUuid);
				tmpUuid = cropUuid;
			} catch(Exception e) {
				e.printStackTrace();
			}
		}

		// Persist from tmp to repo		
		try {
			storageService.persistTmpObject(ResourceTypes.TYPE_IMAGE, Integer.parseInt(subtype), tmpUuid, uuid);
		} catch (Exception e) {
			e.printStackTrace();
			return new Result(ErrorType.SYSTEM_ERROR);
		}		
		return new Result(tmpUuid);
	}
}
